module NC_AHB_wrapper #(
    parameter BASE_ADDRESS = 32'h0200_0000
) (

    input           mclk,

    input           HCLK,
    input           HRESTn,
    input[31:0]     HADDR,
    input           HWRITE,
    input[2:0]      HSIZE,
    input[2:0]      HBURST,
    input[1:0]      HTRANS,
    input[31:0]     HWDATA,
    output          HREADY,
    output          HRESP,
    output[31:0]    HRDATA,

    output      CEn,
    output      WPn,
    output      WE,   
    output      RE,   
    output      CLE,   
    output      ALE,  

    input[7:0]  DQ_i,
    output[7:0] DQ_o, 
    output      DQ_oen, 
    input       DQS_i,
    output      DQS_o,
    output      DQS_oen,
    input       RB
);


reg        so_respon;
reg[31:0]  so_rdata;
reg        so_rdata_valid;
wire[31:0] si_address;
wire       si_write;
wire       si_read;
wire[31:0] si_wdata;


wire[15:0] ECC_cdiv;
wire[15:0] dataclkX2_div;
wire        l_decode_en;
wire        l_code_en;
wire        l_code_success;
wire        l_decode_success;
wire[15:0]  l_page_size;
wire[15:0]  l_ecc_size;
reg[31:0]   l_w_data;
reg         l_w_valid_r;
wire        l_w_en;
wire[31:0]  l_r_data;
wire        l_r_valid;
reg         l_r_en_r;
wire[2:0]   l_cmd;
wire[3:0]   l_cmd_counter;
wire        l_cmd_finish;
wire[39:0]  l_address;
wire[3:0]   l_block_address_num;
wire[3:0]   l_page_address_num;
wire        l_r_can_read;
wire dqs_in;
wire dll_en;
wire dll_locked;
wire[7:0] dll_dly;
reg[3:0] last_cmd_count;
reg[3:0] WDR_counter;
reg[3:0] cmd_count;
assign l_cmd_counter = cmd_count;

reg[31:0] CR;
wire[5:0] FLR;
reg[31:0] PSR;
reg[31:0] AR1;
reg[31:0] AR2;
reg[31:0] CSR;

localparam READ_BUFFER_SIZE = 256;
reg[READ_BUFFER_SIZE - 1 : 0] READ_BUFFER;
reg[8:0] r_buffer_writed;
reg[8:0] r_buffer_readed;
wire[8:0] r_buffer_used;
assign r_buffer_used = r_buffer_readed - r_buffer_writed;

reg[31:0] WDR;
wire data_can_write;
assign data_can_write =  l_w_en && r_buffer_used < 6;

localparam WRITE_BUFFER_SIZE = 256;
reg[WRITE_BUFFER_SIZE - 1 : 0] WRITE_BUFFER;
reg[8:0] w_buffer_writed;
reg[8:0] w_buffer_readed;
wire[8:0] w_buffer_used;
assign w_buffer_used = w_buffer_readed - w_buffer_writed;

wire[31:0] RDR;
wire data_can_read;
assign data_can_read = w_buffer_used > 0 && w_buffer_used <= 6;
assign RDR = l_r_data;

wire all_en;
assign CEn = ~all_en;
assign {l_block_address_num[3:0], l_page_address_num[3:0], dll_dly[7:0]} = CR[31:16];
assign {dll_en, all_en, l_decode_en, l_code_en, l_cmd[2:0]} = CR[6:0];
assign FLR[5:0] = {dll_locked, l_cmd_finish, l_code_success, l_decode_success, data_can_write, data_can_read}; 
assign {l_page_size[15:0], l_ecc_size[15:0]} = PSR;
assign l_address[31:0] = AR1;
assign l_address[39:32] = AR2[7:0];
assign {ECC_cdiv[15:0], dataclkX2_div[15:0]} = CSR;
wire ecc_clk;
wire data_rw_clk;
wire con_clk;

clock_divider u_clock_divider(
	.clk   (mclk                ),
    .rst_n (HRESTn              ),
    .div1  (ECC_cdiv            ),
    .clk1  (ecc_clk             ),
    .div2  (dataclkX2_div       ),
    .clk2  (con_clk             ),
    .div3  (dataclkX2_div >> 1  ),
    .clk3  (data_rw_clk         )
);

DLL_design u_DLL_design(
	.clk    (mclk       ),
    .rst_n  (HRESTn     ),
    .fin    (DQS_i      ),
    .fout   (dqs_in     ),
    .locked (dll_locked ),
    .fin_en (dll_en     ),
    .dly    (dll_dly    )
);

AHB_slave u_AHB_slave(
	.clk                    (HCLK               ),

    .reset_n                (HRESTn             ),
    .ahb_haddr              (HADDR              ),
    .ahb_hwrite             (HWRITE             ),
    .ahb_hsize              (HSIZE              ),
    .ahb_hburst             (HBURST             ),
    .ahb_htrans             (HTRANS             ),
    .ahb_hwdata             (HWDATA             ),
    .ahb_hready             (HREADY             ),
    .ahb_hresp              (HRESP              ),
    .ahb_hrdata             (HRDATA             ),
    .ahb_hprot              (0                  ),
    .ahb_hmastlock          (1                  ),

    .avl_readdata           (so_rdata           ),
    .avl_readdatavalid      (so_rdata_valid     ),
    .avl_waitrequest_n      (1                  ),
    .avl_response           (so_respon          ),
    .avl_address            (si_address         ),
    .avl_write              (si_write           ),
    .avl_read               (si_read            ),
    .avl_burstcount         (                   ),
    .avl_beginbursttransfer (                   ),
    .avl_lock               (                   ),
    .avl_writedata          (si_wdata           )
);

NANDFlash_Control u_NANDFlash_Control(
	.clk            (con_clk          ),
    .rst_n          (HRESTn            ),
    .ECCclk         (ecc_clk          ),
    .decode_en      (l_decode_en      ),
    .code_en        (l_code_en        ),
    .code_success   (l_code_success   ),
    .decode_success (l_decode_success ),
    .page_size      (l_page_size      ),
    .ecc_size       (l_ecc_size       ),
    .w_data         (l_w_data         ),
    .w_valid        (l_w_valid_r      ),
    .w_en           (l_w_en           ),
    .r_data         (l_r_data         ),
    .r_valid        (l_r_valid        ),
    .r_en           (l_r_en_r         ),
    .wr_clk         (data_rw_clk      ),
    .cmd            (l_cmd            ),
    .cmd_counter    (l_cmd_counter    ),
    .cmd_finish     (l_cmd_finish     ),
    .address        (l_address        ),
    .r_can_read     (l_r_can_read     ),
    .block_address_num(l_block_address_num),
    .page_address_num(l_page_address_num),

    .F_WPn          (WPn          ),
    .F_WE           (WE           ),
    .F_RE           (RE           ),
    .F_CLE          (CLE          ),
    .F_ALE          (ALE          ),
    .F_DQ_i         (DQ_i         ),
    .F_DQ_o         (DQ_o         ),
    .F_DQ_oen       (DQ_oen       ),
    .F_DQS_i        (dqs_in       ),
    .F_DQS_o        (DQS_o        ),
    .F_DQS_oen      (DQS_oen      ),
    .F_RB           (RB           )
);

reg[2:0] hsize;
always @(posedge HCLK or negedge HRESTn) begin
    if (!HRESTn) begin
        hsize <= 0;
    end else begin
        hsize <= hsize;
    end
end

always @(negedge HCLK or negedge HRESTn) begin
    if (!HRESTn) begin
        so_rdata_valid <= 0;
        so_respon <= `AHB_HRESP_OKAY;
        so_rdata <= 0;
    end else if (si_read == 1 && si_address < BASE_ADDRESS + 8'd32) begin
        if (si_address >= BASE_ADDRESS && si_address < (BASE_ADDRESS + 4)) begin
            so_rdata_valid <= 1;
            so_rdata <= {CR[31:16], 9'd0, CR[6:0]};
        end else if(si_address >= (BASE_ADDRESS + 4) && si_address < (BASE_ADDRESS + 8))begin
            so_rdata_valid <= 1;
            so_rdata <= {25'h0, FLR[5:0]};
        end else if(si_address >= (BASE_ADDRESS + 8) && si_address < (BASE_ADDRESS + 12))begin
            so_rdata_valid <= 1;
            so_rdata <= PSR;
        end else if(si_address >= (BASE_ADDRESS + 12) && si_address < (BASE_ADDRESS + 16))begin
            so_rdata_valid <= 1;
            so_rdata <= AR1;
        end else if(si_address >= (BASE_ADDRESS + 16) && si_address < (BASE_ADDRESS + 20))begin
            so_rdata_valid <= 1;
            so_rdata <= AR2;
        end else if(si_address >= (BASE_ADDRESS + 20) && si_address < (BASE_ADDRESS + 24))begin
            so_rdata_valid <= 1;
            so_rdata <= CSR;
        end else if(si_address >= (BASE_ADDRESS + 24) && si_address < (BASE_ADDRESS + 28))begin
            so_rdata_valid <= 1;
            so_rdata <= 32'h0;//WDR
        end else if(si_address >= (BASE_ADDRESS + 28) && si_address < (BASE_ADDRESS + 32))begin
            so_rdata_valid <= 1;
            so_rdata <= WRITE_BUFFER >> ((w_buffer_used - 1) * 32);
            w_buffer_writed <= w_buffer_writed + 1;
        end else begin
            so_rdata_valid <= 1;
            so_rdata <= 0;
        end
    end else if (cmd_count != last_cmd_count) begin
        w_buffer_writed <= 0;
    end else begin
        so_respon <= `AHB_HRESP_OKAY;
    end
end




always @(posedge HCLK or negedge HRESTn) begin
    if (!HRESTn) begin
        WDR_counter <= 0;
        cmd_count <= 0;
        CR <= 0;
        PSR <= 0;
        AR1 <= 0;
        AR2 <= 0;
        CSR <= 0;
        WDR <= 0;
        READ_BUFFER <= 0;
        r_buffer_readed <= 0;
    end else if (si_write == 1 && si_address < BASE_ADDRESS + 8'd32) begin
        if (si_address >= BASE_ADDRESS && si_address < (BASE_ADDRESS + 4)) begin
            CR = si_wdata;
            cmd_count <= cmd_count + 1;
            r_buffer_readed <= 0;
            READ_BUFFER <= 0;
        end else if(si_address >= (BASE_ADDRESS + 4) && si_address < (BASE_ADDRESS + 8))begin
            //FLR
        end else if(si_address >= (BASE_ADDRESS + 8) && si_address < (BASE_ADDRESS + 12))begin
            PSR <= si_wdata;
        end else if(si_address >= (BASE_ADDRESS + 12) && si_address < (BASE_ADDRESS + 16))begin
            AR1 <= si_wdata;
        end else if(si_address >= (BASE_ADDRESS + 16) && si_address < (BASE_ADDRESS + 20))begin
            AR2 <= si_wdata;
        end else if(si_address >= (BASE_ADDRESS + 20) && si_address < (BASE_ADDRESS + 24))begin
            CSR <= si_wdata;
        end else if(si_address >= (BASE_ADDRESS + 24) && si_address < (BASE_ADDRESS + 28))begin
            WDR <= si_wdata;
            READ_BUFFER <= {READ_BUFFER[READ_BUFFER_SIZE - 32 : 0], si_wdata};
            r_buffer_readed <= r_buffer_readed + 1;
        end else if(si_address >= (BASE_ADDRESS + 28) && si_address < (BASE_ADDRESS + 32))begin
            //RDR
        end else begin
            CR <= CR;
            PSR <= PSR;
            AR1 <= AR1;
            AR2 <= AR2;
            CSR <= CSR;
            WDR <= WDR;
            cmd_count <= cmd_count;
        end
    end else begin
        CR <= CR;
        PSR <= PSR;
        AR1 <= AR1;
        AR2 <= AR2;
        CSR <= CSR;
        WDR <= WDR;
        cmd_count <= cmd_count;
    end
end

always @(posedge data_rw_clk or negedge HRESTn) begin //WDR -> 控制�?????
    if (!HRESTn) begin
        l_w_valid_r <= 0;
        r_buffer_writed <= 0;
        last_cmd_count <= 0;
        l_w_data <= 0;
    end else begin
        if (cmd_count != last_cmd_count) begin
            last_cmd_count <= cmd_count;
            r_buffer_writed <= 0;
        end else if (l_w_en) begin
            if (r_buffer_used > 0) begin
                l_w_data <= READ_BUFFER >> ((r_buffer_used - 1) * 32);
                r_buffer_writed <= r_buffer_writed + 1; 
                l_w_valid_r <= 1;
            end else begin
                l_w_valid_r <= 0;
            end
        end else begin
            l_w_valid_r <= 0;
        end
    end
end

always @(posedge data_rw_clk or negedge HRESTn) begin //控制�????? -> RDR
    if (!HRESTn) begin
        l_r_en_r <= 0;
    end else begin
         if (l_r_can_read == 1 && w_buffer_used < 6) begin
            l_r_en_r <= 1;
        end else begin
            l_r_en_r <= 0;
        end
    end 
end

always @(posedge data_rw_clk or negedge HRESTn) begin
    if (!HRESTn) begin
        WRITE_BUFFER <= 0;
        w_buffer_readed <= 0;
    end else begin
         if (cmd_count != last_cmd_count) begin
            WRITE_BUFFER <= 0;
            w_buffer_readed <= 0;
         end else if (l_r_can_read == 1 && l_r_valid == 1)begin
            WRITE_BUFFER <= {WRITE_BUFFER[WRITE_BUFFER_SIZE - 1 : 0], l_r_data};
            w_buffer_readed <= w_buffer_readed + 1;
         end else begin
            WRITE_BUFFER <= WRITE_BUFFER;
            w_buffer_readed <= w_buffer_readed; 
         end
    end
end

endmodule